package ca.venasse.pinventory.config;

import static com.google.common.collect.Lists.newArrayList;

import java.util.ArrayList;
import java.util.List;

import org.axonframework.commandhandling.CommandBus;
import org.axonframework.commandhandling.CommandHandlerInterceptor;
import org.axonframework.commandhandling.SimpleCommandBus;
import org.axonframework.commandhandling.annotation.AnnotationCommandHandlerBeanPostProcessor;
import org.axonframework.commandhandling.interceptors.SpringTransactionalInterceptor;
import org.axonframework.eventhandling.EventBus;
import org.axonframework.eventhandling.SimpleEventBus;
import org.axonframework.eventhandling.annotation.AnnotationEventListenerBeanPostProcessor;
import org.axonframework.eventstore.EventUpcaster;
import org.axonframework.eventstore.XStreamEventSerializer;
import org.axonframework.eventstore.jpa.JpaEventStore;
import org.axonframework.eventstore.legacy.LegacyAxonEventUpcaster;
import org.dom4j.Document;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.transaction.PlatformTransactionManager;

@Configuration
public class AxonConfiguration {

	@Bean
	public AnnotationCommandHandlerBeanPostProcessor annotationCommandHandlerBeanPostProcessor(
			CommandBus commandBus) {
		AnnotationCommandHandlerBeanPostProcessor beanPostProcessor = new AnnotationCommandHandlerBeanPostProcessor();
		beanPostProcessor.setCommandBus(commandBus);
		return beanPostProcessor;
	}

	@Bean
	public CommandBus commandBus(PlatformTransactionManager transactionManager) {
		List<CommandHandlerInterceptor> interceptors = newArrayList();

		SpringTransactionalInterceptor transactionalInterceptor = new SpringTransactionalInterceptor();
		transactionalInterceptor.setTransactionManager(transactionManager);
		interceptors.add(transactionalInterceptor);

		SimpleCommandBus commandBus = new SimpleCommandBus();
		commandBus.setInterceptors(interceptors);

		return commandBus;
	}

	@Bean
	public EventBus eventBus() {
		return new SimpleEventBus();
	}

	@Bean
	public AnnotationEventListenerBeanPostProcessor eventListenerPostProcessor(
			ThreadPoolTaskExecutor taskExecutor, EventBus eventBus) {
		AnnotationEventListenerBeanPostProcessor processor = new AnnotationEventListenerBeanPostProcessor();
		processor.setEventBus(eventBus);
		processor.setExecutor(taskExecutor);
		return processor;
	}

	@Bean
	public JpaEventStore eventStore() {
		XStreamEventSerializer eventSerializer = new XStreamEventSerializer();
		ArrayList<EventUpcaster<Document>> upcasters = newArrayList();
		upcasters.add(new LegacyAxonEventUpcaster());
		eventSerializer.setEventUpcasters(upcasters);

		JpaEventStore eventStore = new JpaEventStore(eventSerializer);
		return eventStore;
	}

	@Bean
	public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
		ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
		taskExecutor.setCorePoolSize(20);
		taskExecutor.setMaxPoolSize(100);
		taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
		return taskExecutor;
	}

}
